package com.gitee.cliveyuan.tools.data;

import com.gitee.cliveyuan.tools.*;
import com.gitee.cliveyuan.tools.exception.CsvException;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.PropertyDescriptor;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import static com.gitee.cliveyuan.tools.data.TableUtils.SDF;

/**
 * CSV帮助类
 *
 * @author clive
 * Created on 2018/07/27
 * @since 1.0
 */
public class CsvHelper<T> extends TableAbstract {

    private static final Logger logger = LoggerFactory.getLogger(CsvHelper.class);
    private static final String EXTENSION = ".csv";
    private final static String DEFAULT_ENCODING = "UTF-8";

    /**
     * 生成CSV (默认UTF-8)
     *
     * @param headers  抬头 (要与数据中的属性顺序和数量对应)
     * @param data     数据
     * @param filePath 导出的文件路径
     * @return 导出的文件
     */
    public File generate(String[] headers, Collection<T> data, String filePath) throws CsvException {
        return generate(headers, data, filePath, DEFAULT_ENCODING);
    }

    /**
     * 生成CSV
     *
     * @param headers  抬头 (要与数据中的属性顺序和数量对应)
     * @param data     数据
     * @param filePath 导出的文件路径
     * @param encoding 编码格式
     * @return 导出的文件
     */
    public File generate(String[] headers, Collection<T> data, String filePath, String encoding) throws CsvException {
        Assert.isTrue(CollectionTools.isNotEmpty(headers), "headers can't be empty");
        Assert.isTrue(CollectionTools.isNotEmpty(data), "data can't be empty");
        Assert.notBlank(filePath, "file path can't be empty");
        File file = new File(filePath);
        if (!file.exists()) {
            boolean result = file.mkdirs();
            if (!result) throw CsvException.failToMkdirs();
        }
        String fileName = System.currentTimeMillis() + EXTENSION;
        if (!filePath.endsWith("/")) filePath = filePath + "/";
        file = new File(filePath + fileName);
        try {
            StringBuilder content = new StringBuilder();
            //header
            for (String header : headers) {
                content.append(header).append(",");
            }
            content.deleteCharAt(content.length() - 1);
            content.append("\n");

            //data
            Iterator<T> it = data.iterator();
            while (it.hasNext()) {
                T t = it.next();
                //反射
                Class<?> clazz = t.getClass();
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                    Method getMethod = pd.getReadMethod();
                    if (getMethod != null) {
                        Object invoke = getMethod.invoke(t);
                        String value = StringTools.EMPTY;
                        if (invoke != null) {
                            if (invoke instanceof Date) {
                                value = SDF.format((Date) invoke);
                            } else value = invoke.toString();
                        }
                        content.append(value).append(",");
                    }
                }
                content.deleteCharAt(content.length() - 1);
                content.append("\n");
            }
            FileTools.writeStringToFile(file, content.toString(), encoding);
            return file;
        } catch (Exception e) {
            logger.error("excel generate exception", e);
            throw CsvException.failToGenerateCsv();
        }

    }

    /**
     * 解析CSV (默认UTF-8编码)
     *
     * @param csvPath      csv绝对路径
     * @param skipFirstRow 是否跳过首行
     * @param clazz        类
     * @throws CsvException
     */
    public List<T> parse(String csvPath, boolean skipFirstRow, Class<T> clazz) throws CsvException {
        return parse(csvPath, skipFirstRow, clazz, DEFAULT_ENCODING);
    }

    /**
     * 解析CSV
     *
     * @param csvPath      csv绝对路径
     * @param skipFirstRow 是否跳过首行
     * @param clazz        类
     * @param encoding     编码
     */
    public List<T> parse(String csvPath, boolean skipFirstRow, Class<T> clazz, String encoding) throws CsvException {
        int skipRowNo = 0;
        if (skipFirstRow) skipRowNo = 1;
        return parse(csvPath, skipRowNo, clazz, encoding);
    }

    /**
     * 解析CSV
     *
     * @param csvPath   csv绝对路径
     * @param skipRowNo 跳过前n行
     * @param clazz     类
     */
    public List<T> parse(String csvPath, int skipRowNo, Class<T> clazz, String encoding) throws CsvException {

        try {
            return dataToObject(skipRowNo, CsvTools.readCsv(csvPath, encoding), clazz);
        } catch (IllegalArgumentException | CsvException e) {
            throw e;
        } catch (Exception e) {
            logger.error("parse", e);
            throw CsvException.failToParseCsv();
        }


    }


}
